package com.flow.framework.lock.helper;

import com.flow.framework.common.error.SystemErrorCode;
import com.flow.framework.common.exception.CheckedException;
import com.flow.framework.common.util.verify.VerifyUtil;
import com.flow.framework.core.constant.FrameworkCoreConstant;
import com.flow.framework.core.service.properties.ISystemConfigPropertiesService;
import com.flow.framework.lock.properties.FrameworkLockConfigProperties;
import com.flow.framework.lock.service.lock.impl.FastLockServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.*;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;

import java.util.List;

/**
 * 初始化LockHelper
 *
 * @author luoguopiao
 * @version 0.0.1
 * @date 2022/3/13
 */
@Slf4j
@RequiredArgsConstructor
public class LockHelperConfig implements InitializingBean {

    private final ISystemConfigPropertiesService systemConfigPropertiesService;

    private final FrameworkLockConfigProperties frameworkLockConfigProperties;

    @Override
    @SuppressWarnings("deprecation")
    public void afterPropertiesSet() throws Exception {
        Boolean enable = frameworkLockConfigProperties.getEnable();
        if (!VerifyUtil.isTrue(enable)) {
            return;
        }
        String appName = systemConfigPropertiesService.getConfigValue(FrameworkCoreConstant.SERVICE_NAME_KEY, "unknown");
        RedisProperties redisProperties = frameworkLockConfigProperties.getRedis();
        if (null == redisProperties) {
            log.error("lock config is null.");
            throw new CheckedException(SystemErrorCode.SYSTEM_START_ERROR);
        }
        String redisProtocolPrefix;
        if (redisProperties.isSsl()) {
            redisProtocolPrefix = "rediss://";
        } else {
            redisProtocolPrefix = "redis://";
        }
        RedissonClient redissonClient;
        Config config = new Config();
        if (!VerifyUtil.isEmpty(redisProperties.getCluster()) && !VerifyUtil.isEmpty(redisProperties.getCluster().getNodes())) {
            ClusterServersConfig clusterServersConfig = config.useClusterServers();

            //集群状态扫描间隔时间（感知集群主从切换），单位是毫秒
            clusterServersConfig.setScanInterval(2000);
            List<String> nodeList = redisProperties.getCluster().getNodes();
            for (String node : nodeList) {
                clusterServersConfig.addNodeAddress(redisProtocolPrefix + node);
            }
            configCluster(clusterServersConfig, redisProperties);
            redissonClient = Redisson.create(config);
            log.debug("redisson client cluster server load success");
        } else if (!VerifyUtil.isEmpty(redisProperties.getSentinel()) && !VerifyUtil.isEmpty(redisProperties.getSentinel().getNodes())) {
            SentinelServersConfig sentinelServersConfig = config.useSentinelServers();
            sentinelServersConfig.setMasterName(redisProperties.getSentinel().getMaster());
            List<String> nodeList = redisProperties.getSentinel().getNodes();
            for (String node : nodeList) {
                sentinelServersConfig.addSentinelAddress(redisProtocolPrefix + node);
            }

            //集群状态扫描间隔时间（感知集群主从切换），单位是毫秒
            sentinelServersConfig.setScanInterval(2000);
            configCluster(sentinelServersConfig, redisProperties);
            redissonClient = Redisson.create(config);
            log.debug("redisson client sentinel server load success");
        } else {
            SingleServerConfig singleServerConfig = config.useSingleServer();
            singleServerConfig.setPingConnectionInterval(3000);

            //单点模式 可以用"redis://"来启用SSL连接
            singleServerConfig.setAddress(redisProtocolPrefix + redisProperties.getHost() + ":" + redisProperties.getPort());
            if (!VerifyUtil.isEmpty(redisProperties.getPassword())) {
                singleServerConfig.setPassword(redisProperties.getPassword());
            }
            if (!VerifyUtil.isEmpty(redisProperties.getDatabase())) {
                singleServerConfig.setDatabase(redisProperties.getDatabase());
            }
            singleServerConfig.setConnectionPoolSize(redisProperties.getLettuce().getPool().getMaxActive());
            singleServerConfig.setConnectionMinimumIdleSize(redisProperties.getLettuce().getPool().getMaxIdle());
            redissonClient = Redisson.create(config);
            log.debug("redisson client single server load success");
        }
        LockHelper.setFastLockService(new FastLockServiceImpl(redissonClient));
        LockHelper.setApplicationName(appName);
    }

    private <T extends BaseMasterSlaveServersConfig<T>> void configCluster(BaseMasterSlaveServersConfig<T> config,
                                                                           RedisProperties redisProperties) {
        String password = redisProperties.getPassword();
        if (!VerifyUtil.isEmpty(password)) {
            config.setPassword(password);
        }
        config.setPingConnectionInterval(3000);
        config.setMasterConnectionPoolSize(redisProperties.getLettuce().getPool().getMaxActive());
        config.setMasterConnectionMinimumIdleSize(redisProperties.getLettuce().getPool().getMaxIdle());
        config.setSlaveConnectionPoolSize(redisProperties.getLettuce().getPool().getMaxActive());
        config.setSlaveConnectionMinimumIdleSize(redisProperties.getLettuce().getPool().getMaxIdle());
    }
}
